你就要開始讀伊塔羅•卡爾維諾的新小說《如果在冬夜,一個旅人》。
— 卡爾維諾《如果在冬夜,一個旅人》
Clojure 程式開始於一串文字,經由讀取器 (Reader) 把程式轉化成資料結構;詮釋資料 (Metadata) 則是描述資料的資料,或者可以稱作元資料或中介資料。本篇文章將介紹讀取器以及詮釋資料的相關知識。
Clojure 程式的生命由一串文字開始,讀取器 (Reader) 將文字解析之後,產生出編譯器 (Compiler) 可以認識的資料結構。
讀取器嘗試將文字解析成形式 (Form) 或稱作運算式 (Expression),而形式 (Form) 是指任何可以順利被求值 (Evaluation) 的合法程式單元。
任何可以順利被求值的程式單元,包括下列幾種:
任何以非數字開頭的文字皆是符號,符號名稱可以有四則運算字符以及問號,它的型態爲 clojure.lang.Symbol。
常值 (Literal) 指的是程式中代表固定值的連續字符。Clojure 中的常值共有以下幾種:
字串 (String)
任何以雙引號 (") 包覆的字符會被看成字串,它的型態跟 Java 中的字串一樣,皆是 java.lang.String。
數字 (Number)
以數字字符開頭的連續字符,共有整數 (Integer)、浮點數 (Float) 以及有理數 (Ratio)。型態分別爲 java.lang.Long、clojure.lang.BigInt、java.lang.Double 以及 clojure.lang.Ratio。
字符 (Character)
字符以反斜線 (\) 開頭,與實際的字符相對應。型態爲 java.lang.Character。
nil
代表虛無與不存在,與 Java 中的 null 相同意思。
布林 (Boolean)
由 true
與 false
代表邏輯上的真與假。型態爲 java.lang.Boolean。
關鍵字 (Keyword)
由冒號 (:) 開頭的連續字符被當作關鍵字,與符號類似,大半用作索引值。型態爲 clojure.lang.Keyword。
以左右小括號 (()
) 圍起,內部可以是任何形式 (Form)。型態爲 clojure.lang.PersistentList。
以左右中括號 ([]
) 圍起,內部可以是任何的形式 (Form)。型態爲 clojure.lang.PersistentVector。
以左右大括號 ({}
) 圍起,內部是索引與值的對應關係,稱爲向量。索引與值可以是任何的形式 (Form)。型態爲 clojure.lang.PersistentHashMap、clojure.lang.PersistentArrayMap 或 clojure.lang.PersistentTreeMap。
以大括弧 ({}
) 圍起任何形式,並在前面加上井號 (#) 被當作集合。型態爲 clojure.lang.PersistentHashSet 或 clojure.lang.PersistentTreeSet。
有一些字符經由讀取器解析時,會執行特殊的行爲,這些字符被稱爲讀取巨集 (Reader macro)。在 LISP 程式語言中,除了內建的讀取巨集之外,使用者還可以自定讀取巨集,用以改變讀取器的行爲。而在 Clojure 中,讀取巨集則無法讓使用者自行訂製。
以下列出 Clojure 中會被視爲讀取巨集的各種字符:
如果單引號 (') 放置在任何符號前面,將會抑制 Clojure 對符號求值,將該符號原封不動返回,這種行爲稱爲引用 (Quote)。 與使用 quote
函式功能一樣。
而遇到反斜線 (\) 時,讀取器則會將它其後字符返回,成爲字符常值 (Character literal)。
解析到分號 (;) 則會將其後的字符忽略不做解析,是爲註解 (Comment)。
小老鼠符號則是會呼叫 deref
函式,取出其後的參數所引導的值,稱爲標的 (De-reference)。用在取出參考類型所儲存的值,或是等待由 promise
與 future
函式產生的延遲運算,計算完畢返回。
插入符號 (^) 會伴隨着一個映射,其中是一些對於映射之後物件的描述資訊,這些資訊稱作詮釋資料 (Metadata)。與函式 with-meta
的功能一樣。
之後的小節將會有詮釋資料的詳細介紹。
根據井字符號 (#) 之後的字符,讀取器會有不同的行爲,所以井字符號被稱作發派 (Dispatch) 巨集。以下是與井字符號搭配的各字符說明:
#{}
集合。
#""
正則表達式。
#'
傳回之後符號所代表的 Var 物件,與 var
函式相同。
#()
匿名函式。
#_
之後的形式將會被讀取器忽略。
反引號 (`) (位置在鍵盤按鍵 1 左邊) 被稱爲語法引用 (Syntax quote),是 Clojure 巨集中使用的特殊符號之一,用來產生文字範本 (Template),範本中的形式將不會被求值。後續的章節將會有詳細的介紹。
波浪號 (~) 被稱爲解引用 (Unquote),使用在反引號建立的文字範本內,讓波浪號後面跟隨的符號跳出範本而求值。
若波浪號 (~) 之後是小老鼠符號 (@),則被稱爲解引用拼接 (Unquote splice)。它的功用是將範本中的列表解消,替換成列表中的各個元素。
(未完待續)